package com.mp.approvalreq.util;

import com.mp.approvalreq.entity.*;
import com.mp.auth.entity.CommonSetting;
import com.mp.auth.service.CommonSettingServicePrx;
import com.mp.user.entity.User;
import com.mp.user.service.UserServicePrx;
import com.mp.user.util.UserUtils;
import com.plusmoney.util.Utils;
import com.qq.tars.client.util.ServantUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

public class OperationUtils {

    private static final Logger logger = LoggerFactory.getLogger(OperationUtils.class);

    public static List<Integer> getOperations(User user, Request request) throws Throwable {
        List<Integer> operations = new ArrayList<>();

        switch (request.getFinished()) {
            case Finished.APPROVING:
                if (checkConfirmAndRefuse(request, user)) {
                    // 批准驳回
                    operations.add(Operation.REFUSE);
                    operations.add(Operation.CONFIRM);
                    return operations;
                }
                if (checkWithdrawConfirm(request, user)) {
                    // 撤销批准
                    operations.add(Operation.WITHDRAW_APPROVE);
                }
                if (checkWithdrawApply(request, user)) {
                    // 撤销申请
                    operations.add(Operation.WITHDRAW_APPLY);
                }
                break;
            case Finished.AGREED:
                if (checkConfirmAndRefuse(request, user)) {
                    if (checkIsLastFinancialFlow(request, user)) {
                        // 付款/驳回
                        operations.add(Operation.REFUSE);
                        operations.add(Operation.FINANCIAL_CONFIRM);
                    } else {
                        // 批准驳回
                        operations.add(Operation.REFUSE);
                        operations.add(Operation.CONFIRM);
                    }
                    return operations;
                }
                if (checkWithdrawFinancialConfirm(request, user)) {
                    // 撤销批准
                    operations.add(Operation.WITHDRAW_APPROVE);
                }
                if (checkArchive(request, user)) {
                    // // 归档
                    operations.add(Operation.ARCHIVE);
                } else if (checkWithdrawArchive(request, user)) {
                    // 撤销归档
                    operations.add(Operation.WITHDRAW_ARCHIVE);
                }
                // 作废
                if (checkCancel(request, user)) {
                    operations.add(Operation.CANCEL);
                }
                break;
            case Finished.ARCHIVED:
                if (checkWithdrawArchive(request, user)) {
                    // 撤销归档
                    operations.add(Operation.WITHDRAW_ARCHIVE);
                }
                break;
            case Finished.CALLING_BACK:
            case Finished.REFUSED:
                if (checkEdit(request, user)) {
                    operations.add(Operation.EDIT);
                }
            default:

        }
        if (checkPauseLeave(request, user)) {
            // 销假
            operations.add(Operation.PAUSE_LEAVE);
        } else if (checkWithdrawPauseLeave(request, user)) {
            operations.add(Operation.WITHDRAW_PAUSE_LEAVE);
        } else if (checkPauseOutdoor(request, user)) {
            if (request.getDefaultType() == Template.OUTDOOR) {
                // 结束外出
                operations.add(Operation.PAUSE_OUTDOOR);
            } else {
                // 结束出差
                operations.add(Operation.PAUSE_BUSINESS_TRIP);
            }
        }
        if (checkDelete(request, user)) {
            operations.add(Operation.DELETE);
        }

        logger.info("operations:{}", operations);
        if (operations.size() > 2) {
            operations = operations.subList(0, 2);
        }
        return operations;
    }

    private static boolean checkEdit(Request request, User user) {
        return (Objects.equals(request.getApplicant(), user.getContactId()) || Objects.equals(request.getProxyContactId(), user.getContactId()))
                && Utils.isNotNull(request.getLatestTemplateId());
    }

    private static boolean checkDelete(Request request, User user) {
        return request.getFinished() == Finished.CALLING_BACK && Objects.equals(request.getApplicantCiid(), user.getCompanyInfoId());
    }

    private static boolean checkPauseOutdoor(Request request, User user) throws Throwable {
        if (request.getFinished() != Finished.AGREED && request.getFinished() != Finished.ARCHIVED) {
            return false;
        }
        Outdoor outdoor = request.getOutdoor();
        if (Utils.isNull(outdoor)) {
            return false;
        }
        Date now = new Date();
        if (outdoor.getEnd().before(now)) {
            return false;
        }
        if (Objects.equals(request.getApplicantCiid(), user.getCompanyInfoId())) {
            return true;
        }
        if (FlowUtils.isExistUserFlow(request.getFlows(), user)) {
            return true;
        }
        UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);
        return userServicePrx.isLeader(user.getContactId(), request.getApplicant());
    }

    private static boolean checkWithdrawPauseLeave(Request request, User user) throws Throwable {
        Leave leave = request.getLeave();
        if (Utils.isNull(leave)) {
            return false;
        }
        if (!Objects.equals(leave.getIsLeavePause(), 1)) {
            return false;
        }
        if (leave.getRealEndTime().before(new Date())) {
            return false;
        }
        if (Objects.equals(request.getApplicantCiid(), user.getCompanyInfoId())) {
            return true;
        }
        if (FlowUtils.isExistUserFlow(request.getFlows(), user)) {
            return true;
        }
        UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);
        return userServicePrx.isLeader(user.getContactId(), request.getApplicant());
    }

    private static boolean checkPauseLeave(Request request, User user) throws Throwable {
        if (request.getFinished() != Finished.AGREED && request.getFinished() != Finished.ARCHIVED) {
            return false;
        }
        Leave leave = request.getLeave();
        if (Utils.isNull(leave)) {
            return false;
        }

        if (leave.getRealEndTime().before(new Date())) {
            return false;
        }
        try {
            CommonSettingServicePrx commonSettingServicePrx = ServantUtils.getObject(CommonSettingServicePrx.class);
            CommonSetting commonSetting = commonSettingServicePrx.getCommonSetting(user.getCompanyId(), "approve", "pauseLeaveLimit");
            if (!"1".equals(commonSetting.getContent())) {
                logger.info("设置不允许销假");
                return false;
            }
        } catch (Throwable throwable) {
            logger.error(throwable.getMessage(), throwable);
            EmailUtils.sendMail("获取销假设置出错", throwable);
        }
        if (Objects.equals(request.getApplicantCiid(), user.getCompanyInfoId())) {
            return true;
        }
        if (FlowUtils.isExistUserFlow(request.getFlows(), user)) {
            return true;
        }
        UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);
        return userServicePrx.isLeader(user.getContactId(), request.getApplicant());
    }

    private static boolean checkCancel(Request request, User user) {
        if (UserUtils.isAdmin(user)) {
            return true;
        }
        List<Flow> lastFlows = FlowUtils.getLastFlows(request.getFlows());
        if (Objects.equals(Utils.getFirst(lastFlows).getFlowType(), Flow.FLOW_TYPE_FINANCIAL)) {
            return false;
        }
        return FlowUtils.isExistUserFlow(lastFlows, user);
    }


    private static boolean checkWithdrawApply(Request request, User user) {
        if (!Objects.equals(request.getApplicantCiid(), user.getCompanyInfoId())
                && !Objects.equals(request.getProxyContactId(), user.getContactId())) {
            return false;
        }
        return !FlowUtils.existConfirmOrRefuse(request.getFlows());
    }

    private static boolean checkWithdrawFinancialConfirm(Request request, User user) {
        if (request.getFinancialStatus() == 2) {
            // 已付款
            return false;
        }
        if (Utils.isEmpty(FlowUtils.getFinancialFlows(request.getFlows()))){
            return false;
        }
        Flow flow = FlowUtils.getLastConfirmByCompanyInfoId(request.getFlows(), user.getCompanyInfoId());
        if (Utils.isNull(flow)) {
            return false;
        }
        if (!flow.hasConfirmed()) {
            return false;
        }
        List<Flow> nextFlows = FlowUtils.getFlowsByOrdering(request.getFlows(), flow.getOrdering() + 1);
        return !FlowUtils.existConfirmOrRefuse(nextFlows);
    }

    private static boolean checkWithdrawConfirm(Request request, User user) {
        Flow flow = FlowUtils.getLastConfirmByCompanyInfoId(request.getFlows(), user.getCompanyInfoId());
        if (Utils.isNull(flow)) {
            return false;
        }
        if (!flow.hasConfirmed()) {
            return false;
        }
        List<Flow> nextFlows = FlowUtils.getFlowsByOrdering(request.getFlows(), flow.getOrdering() + 1);
        return !FlowUtils.existConfirmOrRefuse(nextFlows);
    }

    private static boolean checkIsLastFinancialFlow(Request request, User user) {
        if (!Objects.equals(request.getIsFinancial(), 1)) {
            return false;
        }
        List<Flow> currentFlows = FlowUtils.getCurrentFlows(request.getFlows());
        if (Utils.isEmpty(currentFlows)) {
            return false;
        }
        Flow nextFlow = currentFlows.get(0);
        if (nextFlow.getFlowType() != Flow.FLOW_TYPE_FINANCIAL) {
            return false;
        }
        return Utils.isEmpty(FlowUtils.getFlowsByOrdering(request.getFlows(), nextFlow.getOrdering() + 1));
    }

    private static boolean checkConfirmAndRefuse(Request request, User user) {
        List<Flow> currentFlows = FlowUtils.getCurrentFlows(request.getFlows());
        return currentFlows.stream().filter(currentFlow -> Objects.equals(currentFlow.getCompanyInfoId(), user.getCompanyInfoId())).anyMatch(currentFlow -> currentFlow.getIsApproved() == Flow.APPROVING);
    }

    private static boolean checkWithdrawArchive(Request request, User user) {
        Cc cc = CcUtils.getCcByCompanyInfoId(request.getCcList(), user.getCompanyInfoId());
        if (Utils.isNull(cc)) {
            return false;
        }
        return cc.getFiledStatus() == Cc.HAD_FILED;
    }

    private static boolean checkArchive(Request request, User user) {
        Cc cc = CcUtils.getCcByCompanyInfoId(request.getCcList(), user.getCompanyInfoId());
        if (Utils.isNull(cc)) {
            return false;
        }
        return cc.getFiledStatus() == Cc.NEED_FILE;
    }

}
